﻿using SkiaSharp;

namespace Service.Core.Utils.VerificationCodeUtil
{
    /// <summary>
    /// 问答式图片验证码,目前是数字计算
    /// </summary>
    public partial class QuestionAnsweringVerificationCodeService : IVerificationCodeService
    {
        //字体颜色
        private static List<SKColor> _colors =
        [
            SKColors.Red,SKColors.DarkBlue,SKColors.DarkRed,SKColors.Black,SKColors.Blue
        ];

        public async Task<VerfyCode> CreateVerificationCode()
        {
            var length = 3;
            return await Task.FromResult(CreateCodeImage(width: length * 40, length: length));
        }

        /// <summary>
        /// 创建题目以及答案
        /// </summary>
        /// <param name="min">最小值</param>
        /// <param name="max">最大值</param>
        /// <param name="len">字符长度</param>
        /// <returns>验证码字符</returns>
        private static (string code, int result) CreateMixVerifyCode(int min, int max, int len)
        {
            // 计算符号
            char[] computeSymbols = { '+', '-', '*', '÷' };
            Random random = new Random();
            List<string> strings = new List<string>();

            // 随机生成多位数字和计算符号
            for (int i = 0; i < len; i++)
            {
                var num = random.Next(min, max + 1);
                strings.Add(num.ToString()); // 数字
                if (i != len - 1)
                {
                    var computeSymbol = random.Next(0, computeSymbols.Length);
                    strings.Add(computeSymbols[computeSymbol].ToString()); // 计算符号
                }
            }

            // 组合成计算公式
            var calculationFormula = string.Join(" ", strings);

            // 调用 Calculate 方法计算结果
            var calculationResult = Calculate(calculationFormula);

            // 确保结果为正整数
            if (calculationResult <= 0)
            {
                return CreateMixVerifyCode(min, max, len); // 重新生成公式
            }

            // 返回计算公式和结果
            return ($"{calculationFormula} = ", calculationResult);
        }

        /// <summary>
        /// 计算结果
        /// </summary>
        /// <param name="formula">计算公式</param>
        /// <returns>结果</returns>
        private static int Calculate(string formula)
        {
            // 拆分公式
            var tokens = formula.Split(' ');

            // 先处理乘除
            for (int i = 1; i < tokens.Length - 1; i += 2)
            {
                if (tokens[i] == "*" || tokens[i] == "÷")
                {
                    var leftNum = int.Parse(tokens[i - 1]);
                    var rightNum = int.Parse(tokens[i + 1]);

                    // 处理除法，确保结果为整数
                    if (tokens[i] == "÷" && rightNum != 0)
                    {
                        while (leftNum % rightNum != 0) // 确保整除
                        {
                            rightNum = new Random().Next(1, rightNum); // 随机生成一个新的右操作数
                        }
                    }

                    var result = Compute(leftNum, tokens[i], rightNum);

                    // 更新 tokens 数组
                    tokens[i - 1] = result.ToString();
                    for (int j = i; j < tokens.Length - 2; j++)
                    {
                        tokens[j] = tokens[j + 2];
                    }
                    Array.Resize(ref tokens, tokens.Length - 2);
                    i -= 2; // 调整索引以重新检查新位置
                }
            }

            // 然后处理加减
            int calculationResult = int.Parse(tokens[0]);
            for (int i = 1; i < tokens.Length; i += 2)
            {
                var computeSymbol = tokens[i];
                var rightNum = int.Parse(tokens[i + 1]);
                calculationResult = Compute(calculationResult, computeSymbol, rightNum);
            }

            return calculationResult;
        }

        private static int Compute(int leftNum, string computeSymbol, int rightNum)
        {
            switch (computeSymbol)
            {
                case "+":
                    return leftNum + rightNum;
                case "-":
                    return leftNum - rightNum;
                case "*":
                    return leftNum * rightNum;
                case "÷":
                    return rightNum != 0 ? leftNum / rightNum : 0;
                default:
                    throw new NotImplementedException();
            }
        }

        public VerfyCode CreateCodeImage(int width = 100, int height = 40, int lineNum = 4, int lineStrookeWidth = 2, int length = 3)
        {
            var verifyCode = CreateMixVerifyCode(1, 100, length);
            //创建bitmap位图
            using SKBitmap image2d = new SKBitmap(width, height, SKColorType.Bgra8888, SKAlphaType.Premul);
            //创建画笔
            using SKCanvas canvas = new SKCanvas(image2d);
            //填充白色背景颜色
            canvas.DrawColor(SKColors.White);
            var array = verifyCode.code.ToArray();
            Random random = new Random();
            for (int i = 0; i < array.Length; i++)
            {
                //将文字写到画布上
                using SKPaint drawStyle = CreatePaint(random.Next(_colors.Count), 20);
                using SKFont font = CreateFont(20);
                canvas.DrawText(array[i].ToString(), i * 8 + 1, height - 10, font, drawStyle);
            }
            //画随机干扰线
            using (SKPaint drawStyle = new SKPaint())
            {
                for (int i = 0; i < lineNum; i++)
                {
                    drawStyle.Color = _colors[random.Next(_colors.Count)];
                    drawStyle.StrokeWidth = lineStrookeWidth;
                    canvas.DrawLine(random.Next(0, width), random.Next(0, height), random.Next(0, width), random.Next(0, height), drawStyle);
                }
            }
            //返回图片byte
            using SKImage img = SKImage.FromBitmap(image2d);
            using SKData p = img.Encode(SKEncodedImageFormat.Jpeg, 100);
            return new VerfyCode() { VerfyByte = p.ToArray(), Code = verifyCode.result.ToString() };
        }
        // 创建画笔
        private SKPaint CreatePaint(int colorNo, float fontSize)
        {
            SKFontStyle sKFontStyle = new SKFontStyle(SKFontStyleWeight.Normal, SKFontStyleWidth.Normal, SKFontStyleSlant.Italic);
            SKFont font = new SKFont(SKTypeface.FromFamilyName("微软雅黑", sKFontStyle), fontSize);
            SKPaint paint = new SKPaint();
            paint.IsAntialias = true;
            paint.Color = _colors[colorNo];
            return paint;
        }

        private SKFont CreateFont(float fontSize)
        {
            SKFontStyle sKFontStyle = new SKFontStyle(SKFontStyleWeight.Normal, SKFontStyleWidth.Normal, SKFontStyleSlant.Italic);
            SKFont font = new SKFont(SKTypeface.FromFamilyName("微软雅黑", sKFontStyle), fontSize);
            return font;
        }


    }
}
